#include "Server.h"

#include "misc/Event.h"
#include "server/misc/Config.h"
#include "server/net/sMsg.h"
#include "server/ui/uiBase.h"
#include "misc/Interface.h"
/*********************************************************/
void Server::run()
{
	// Acquire the singletons
	Config& cfg = Config::Instance();
	Interface& intf = Interface::Instance();
	Event* event = Event::Instance(cfg.getActivateProcessingEvent());
	sMsg* job = 0;

	// Keep some configuration parameters local for fast access
	float threshold = cfg.getThreadPoolThreshold();
	bool mtJobs = cfg.getMultithreadedJobExecution();
	bool uiEcho = cfg.getUIEcho();
	int minThreads = cfg.getThreadPoolMin();

	// Enter the main server loop
	while( true ) {
		// Wait for a processing event
		event->wait();

		// Halt flag
		mutex.lock();
		if ( halt ) {
			tPool.joinAll();		// Wait for all jobs to finish
			mutex.unlock();
			return;
		}
		mutex.unlock();

		// Check the thread pool for congestion!
		if ( mtJobs ) {
			if ((((float)tPool.available())/((float)tPool.capacity()) < threshold ) || ( tPool.available() < minThreads )) {
				tPool.addCapacity(minThreads);		// Add an additional 5 threads
			}
		}
		
		// Handle all jobs received ( Unicast jobs )
		while ( netCtrl->available() ) {
			job = netCtrl->pop();
			if ( job ) {
				try {
					if ( mtJobs ) tPool.start(*job);
					else job->execute();
				} catch( Poco::NoThreadAvailableException& e ) {
					tPool.addCapacity(minThreads);		// Increase capacity
					tPool.start(*job);
				}
			}
		}

		// Handle all interface input
		std::string command;
		while (intf.pop(command)) {
			if ( uiEcho ) intf << command << std::endl;

			uiBase* cmd = uiBase::parse(command);
			if ( cmd ) cmd->execute();
		}
	}
}
/*********************************************************/
void Server::start()
{
	// Get the needed singletons
	Config& cfg = Config::Instance();
	Event* event = Event::Instance(cfg.getActivateProcessingEvent());

	// no need to start a thread that is allready running
	if ( lThread.isRunning() ) return;

	// Set the initial values
	mutex.lock();
	halt = false;
	event->reset();
	mutex.unlock();

	// Start the thread
	lThread.start((*this));
}
/*********************************************************/
void Server::stop()
{
	// Get the needed singletons
	Config& cfg = Config::Instance();
	Event* event = Event::Instance(cfg.getActivateProcessingEvent());

	// No need to stop a thread that isn't running
	if ( !lThread.isRunning() ) return;

	// Set the halt flag
	mutex.lock();
	halt = true;
	event->set();
	mutex.unlock();

	// Wait for the thread to exit
	while ( lThread.isRunning() ) lThread.tryJoin(25);
}
/*********************************************************/
Server::Server()
{
	// Get the pointer to the middleware
	netCtrl = &NetworkControl::Instance();
}
/*********************************************************/
Server::~Server()
{
}
